package hello.world;

import android.os.SystemClock;
import android.view.MotionEvent;

public class UpdateThread implements Runnable
{
    private boolean done;
    private boolean running;
    private long lastTime = -1L;
    private static final long TIME_STEP = 1000000000L / 60L;
    private static final long MAX_ACCUMULATED_TIME = 1000000000L / 10L;
    private long accumulator = 0;
    private long pauseTime;
    private final SpritesHolder spritesHolder;
    private float animeTimer = 0.0f;
    private float skullTimer = 0.0f;
    private float2 mousePosition = new float2();   // in game coords
    private final int2 screenSize;

    public UpdateThread(SpritesHolder _spritesHolder, int2 _screenSize)
    {
        spritesHolder = _spritesHolder;
        screenSize = _screenSize;
    }
    
    public void update(float delta)
    {
        synchronized (spritesHolder)
        {
            animeTimer += delta * 0.3f;
            spritesHolder.anime.setPosition(
                new float2((float)Math.cos(animeTimer * 2.0 * Math.PI) * 300.0f,
                384.0f + (float)Math.sin(animeTimer * 2.0 * Math.PI) * 300.0f));
            spritesHolder.anime.setRotation(-animeTimer * 360.0f);
            if (skullTimer > 0.0f)
            {
                skullTimer -= delta;
            }
            spritesHolder.skull.setAlpha(skullTimer);
            spritesHolder.skull.setPosition(mousePosition);
        }
    }
    
    public void run()
    {
        done = false;
        running = true;
        long delta;
        while (!spritesHolder.isLoaded())
        {
            try
            {
                Thread.sleep(100);
            }
            catch (InterruptedException e)
            {
                System.err.println("Thread.sleep exception: " + e.getMessage());
            }
        }
        while (!done)
        {
            if (running)
            {
                if (lastTime == -1L)
                {
                    lastTime = System.nanoTime();
                    continue;
                }
                long currTime = System.nanoTime();
                delta = currTime - lastTime;
                lastTime = currTime;
                if (delta < 0)
                    delta = 0;
                accumulator += delta;
                if (accumulator > MAX_ACCUMULATED_TIME)
                {
                    accumulator = MAX_ACCUMULATED_TIME;
                }
                while (accumulator >= TIME_STEP)
                {
                    update(1.0f / 60.0f);
                    accumulator -= TIME_STEP;
                }
                
                long sleepTime = 10-((System.nanoTime()-currTime)/1000000L);
                try
                {
                    if(sleepTime>0)
                        Thread.sleep(sleepTime);
                } catch (InterruptedException ex) 
                {
                }
            }
            else
            {
                try
                {
                    Thread.sleep(100);
                }
                catch (InterruptedException e)
                {
                    System.err.println("Thread.sleep exception: " + e.getMessage());
                }
            }
        }
    }
    
    public void pause()
    {
        if (running)
        {
            running = false;
            pauseTime = SystemClock.uptimeMillis();
        }
    }
    
    public void unpause()
    {
        if (!running)
        {
            running = true;
            lastTime += SystemClock.uptimeMillis() - pauseTime;
        }
    }
    
    public void kill()
    {
        done = true;
    }
    
    /* WARNING! Method called by ANOTHER THREAD,
     * so one CAN'T use spritesHolder here!
     * Only save important input information
     * and use it later in update(float delta).
     */
    public boolean onTouchEvent(MotionEvent e)
    {
        switch (e.getAction())
        {
            case MotionEvent.ACTION_UP:
                float height = screenSize.y;
                mousePosition = new float2((e.getX() - screenSize.x * 0.5f) * 768.0f / height,
                    e.getY() * 768.0f / height);
                skullTimer = 1.0f;
                break;
        }
        return true;
    }
}
